/*
 * Copyright (C) 2021 The Chinese Software International Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.tonyodev.fetch2.util;

import ohos.eventhandler.EventRunner;
import ohos.utils.net.Uri;

import com.tonyodev.fetch2.Download;
import com.tonyodev.fetch2.Request;
import com.tonyodev.fetch2.fetch.FetchHandler;
import com.tonyodev.fetch2core.Downloader;
import com.tonyodev.fetch2core.Extras;
import com.tonyodev.fetch2core.FetchCoreUtils;
import com.tonyodev.fetch2core.FileSliceInfo;

import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static com.tonyodev.fetch2core.FetchCoreUtils.GET_REQUEST_METHOD;

/**
 * description FetchUtils
 *
 * @author liuluming
 * @since 2021-05-24
 */

public class FetchUtils {

    public static boolean canPauseDownload(Download download) {
        switch (download.getStatus()) {
            case DOWNLOADING:
            case QUEUED:
                return true;
            default:
                return false;

        }

    }

    public static boolean canResumeDownload(Download download) {
        switch (download.getStatus()) {
            case ADDED:
            case QUEUED:
            case PAUSED:
                return true;
            default:
                return false;

        }
    }

    public static boolean canRetryDownload(Download download) {
        switch (download.getStatus()) {
            case FAILED:
            case QUEUED:
            case CANCELLED:
                return true;
            default:
                return false;

        }
    }

    public static boolean canCancelDownload(Download download) {
        switch (download.getStatus()) {
            case COMPLETED:
            case NONE:
            case FAILED:
                return true;
            default:
                return false;

        }
    }

    public static Downloader.ServerRequest getRequestForDownload(@NotNull Download download) {
        return getRequestForDownload(download, GET_REQUEST_METHOD);
    }

    public static Downloader.ServerRequest getRequestForDownload(Download download, String requestMethod) {
        return getRequestForDownload(download, -1L, -1L, GET_REQUEST_METHOD, 1);
    }

    public static Downloader.ServerRequest getRequestForDownload(Download download, Long rangeStart, int segment) {
        long start = rangeStart == -1L ? 0L : rangeStart;
        Map<String, String> headers = download.getHeaders();
        headers.put("Range", "bytes=" + start + "-");
        return new Downloader.ServerRequest(download.getId(), download.getUrl(), headers, download.getFile(), FetchCoreUtils.getFileUri(download.getFile()), download.getTag(), download.getIdentifier(), GET_REQUEST_METHOD, download.getExtras(), false, "", segment);
    }

    public static Downloader.ServerRequest getRequestForDownload(Download download, Long rangeStart, Long rangeEnd, int segment) {
        long start = rangeStart == -1L ? 0L : rangeStart;
        String end = rangeEnd == -1L ? "" : String.valueOf(rangeEnd);
        Map<String, String> headers = download.getHeaders();
        headers.put("Range", "bytes=" + start + '-' + end);
        return new Downloader.ServerRequest(download.getId(), download.getUrl(), headers, download.getFile(), FetchCoreUtils.getFileUri(download.getFile()), download.getTag(), download.getIdentifier(), GET_REQUEST_METHOD, download.getExtras(), false, "", segment);
    }

    public static Downloader.ServerRequest getRequestForDownload(Download download, Long rangeStart, Long rangeEnd, String requestMethod, int segment) {
        long start = rangeStart == -1L ? 0L : rangeStart;
        String end = rangeEnd == -1L ? "" : String.valueOf(rangeEnd);
        Map<String, String> headers = download.getHeaders();
        headers.put("Range", "bytes=" + start + '-' + end);
        return new Downloader.ServerRequest(download.getId(), download.getUrl(), headers, download.getFile(), FetchCoreUtils.getFileUri(download.getFile()), download.getTag(), download.getIdentifier(), GET_REQUEST_METHOD, download.getExtras(), false, "", segment);
    }

    @NotNull
    public static Downloader.ServerRequest getServerRequestFromRequest(@NotNull Request request) {
        int id = request.getId();
        String url = request.getUrl();
        Map<String, String> headers = request.getHeaders();
        String tag = request.getTag();
        long mIdentifier = request.getIdentifier();
        String requestMethod = GET_REQUEST_METHOD;
        String file = request.getFile();
        Uri uri = FetchCoreUtils.getFileUri(request.getFile());
        Extras extras = request.getExtras();
        boolean redirected = false;
        String redirectUrl = "";
        int segment = 1;
        return new Downloader.ServerRequest(id, url, headers, file, uri, tag, mIdentifier, requestMethod, extras, redirected, redirectUrl, segment);
    }

    @NotNull
    public static Downloader.ServerRequest getCatalogServerRequestFromRequest(@NotNull Request request) {
        LinkedHashMap<String, String> headers = new LinkedHashMap<>(request.getHeaders());
        headers.put("Range", "bytes=0-");
        headers.put("Page", "-1");
        headers.put("Size", "-1");
        headers.put("Type", String.valueOf(1));
        int id = request.getId();
        String url = request.getUrl();
        String tag = request.getTag();
        long mIdentifier = request.getIdentifier();
        String requestMethod = GET_REQUEST_METHOD;
        String file = request.getFile();
        Uri uri = FetchCoreUtils.getFileUri(request.getFile());
        Extras extras = request.getExtras();
        boolean redirected = false;
        String redirectUrl = "";
        int segment = 1;
        return new Downloader.ServerRequest(id, url, headers, file, uri, tag, mIdentifier, requestMethod, extras, redirected, redirectUrl, segment);
    }

    /**
     * getPreviousSliceCount
     *
     * @param id 1
     * @param fileTempDir fileTempDir
     * @return true
     */
    public static int getPreviousSliceCount(int id, @NotNull String fileTempDir) {
        int sliceCount = -1;

        try {
            Long form = FetchCoreUtils.getLongDataFromFile(getMetaFilePath(id, fileTempDir));
            sliceCount = form != null ? Math.toIntExact(form) : -1;
        } catch (Exception e) {
        }

        return sliceCount;
    }

    @NotNull
    public static String getMetaFilePath(int id, @NotNull String fileTempDir) {
        return fileTempDir + '/' + id + ".meta.data";
    }

    public static void saveCurrentSliceCount(int id, int SliceCount, @NotNull String fileTempDir) {
        try {
            FetchCoreUtils.writeLongToFile(getMetaFilePath(id, fileTempDir), (long) SliceCount);
        } catch (Exception e) {
        }

    }

    @NotNull
    public static String getDownloadedInfoFilePath(int id, int position, @NotNull String fileTempDir) {
        return fileTempDir + '/' + id + '.' + position + ".data";
    }

    /**
     * deleteAllInFolderForId
     *
     * @param id 1
     * @param fileTempDir 1
     */
    public static void deleteAllInFolderForId(int id, @NotNull String fileTempDir) {
        try {
            File dir = new File(fileTempDir);
            if (dir.exists()) {
                File[] files = dir.listFiles();
                if (files != null) {
                    List<File> filteredFilesList = new ArrayList<>();
                    for (File file : files) {
                        String name = file.getName();
                        String substringBeforeLast = (String) substringBeforeLast(name);
                        if (substringBeforeLast.startsWith("" + id)) {
                            filteredFilesList.add(file);
                        }
                    }
                    for (File file : filteredFilesList) {
                        if (file.exists()) {
                            boolean isDelete = file.delete();
                        }
                    }

                }

            }
        } catch (Exception e) {
        }

    }

    private static CharSequence substringBeforeLast(String name) {
        int index = name.lastIndexOf('.');
        if (index == -1) {
            return name;
        } else {
            return name.subSequence(0, index);
        }
    }

    /**
     * getSavedDownloadedInfo
     *
     * @param id 1
     * @param position 1
     * @param fileTempDir fileTempDir
     * @return true
     */
    public static long getSavedDownloadedInfo(int id, int position, @NotNull String fileTempDir) {
        long downloaded = 0L;

        try {
            Long l = FetchCoreUtils.getLongDataFromFile(getDownloadedInfoFilePath(id, position, fileTempDir));
            downloaded = l != null ? l : 0L;
        } catch (Exception e) {
        }

        return downloaded;
    }

    /**
     * getFileSliceInfo
     *
     * @param fileSliceSize 1
     * @param totalBytes 1
     * @return true
     */
    @NotNull
    public static FileSliceInfo getFileSliceInfo(int fileSliceSize, long totalBytes) {
        if (fileSliceSize == -1) {
            float fileSizeInMb = (float) totalBytes / 1024.0F * 1024.0F;
            float fileSizeInGb = (float) totalBytes / 1024.0F * 1024.0F * 1024.0F;
            FileSliceInfo mFileSliceInfo;
            float var;
            byte slices;
            long bytesPerSlice;
            if (fileSizeInGb >= 1.0F) {
                slices = 6;
                var = (float) totalBytes / (float) slices;
                bytesPerSlice = (long) ((float) Math.ceil(var));
                mFileSliceInfo = new FileSliceInfo(slices, bytesPerSlice);
            } else if (fileSizeInMb >= 1.0F) {
                slices = 4;
                var = (float) totalBytes / (float) slices;
                bytesPerSlice = (long) ((float) Math.ceil(var));
                mFileSliceInfo = new FileSliceInfo(slices, bytesPerSlice);
            } else {
                mFileSliceInfo = new FileSliceInfo(2, totalBytes);
            }

            return mFileSliceInfo;
        } else {
            float size = (float) totalBytes / (float) fileSliceSize;
            long bytesPerSlice = (long) ((float) Math.ceil(size));
            return new FileSliceInfo(fileSliceSize, bytesPerSlice);
        }
    }

    /**
     * awaitFinishOrTimeout
     *
     * @param allowTimeInMilliseconds allowTimeInMilliseconds
     * @param fetchHandler fetchHandler
     */
    public static void awaitFinishOrTimeout(long allowTimeInMilliseconds, @NotNull FetchHandler fetchHandler) {
        Thread thread = Thread.currentThread();
        EventRunner looper = EventRunner.getMainEventRunner();
        boolean hasAllowedTimeExpired = false;
        boolean indefinite = allowTimeInMilliseconds == 0L;
        long milliseconds = allowTimeInMilliseconds < 1000 ? allowTimeInMilliseconds : 1000L;
        long sleepTime = indefinite ? 5000L :milliseconds;
        long timeStarted = System.currentTimeMillis();

        for (long pendingCount = fetchHandler.getPendingCount(); indefinite || pendingCount > 0L && !hasAllowedTimeExpired; pendingCount = fetchHandler.getPendingCount()) {
            try {
                Thread.sleep(sleepTime);
            } catch (Exception e) {
            }

            hasAllowedTimeExpired = allowTimeInMilliseconds == -1L ? false : FetchCoreUtils.hasAllowedTimeExpired(timeStarted, System.currentTimeMillis(), allowTimeInMilliseconds);
        }

    }
}
